/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "sle_lite_tool_test.h"
#include "kh_sle_ssap_client.h"
#include "kh_sle_connect.h"

static uint8_t g_test_times = Delay_Test_Time;
static uint8_t g_test_steps = Delay_Test_Step;
static uint16_t g_test_data_len = Delay_Test_Data_Size;
static int g_isReq = 0;
static uint16_t g_delayTestConnectId = 0;
static uint16_t g_delayTestPropHdl = 0;
static osSemaphoreId_t g_delayTestSemHdl = 0;
static uint8_t g_delayTestClientId = 0;
static osThreadId_t g_delayTestThreadId = 0;
static SleConnectionParamUpdate g_delayTestConnPara = {
    .connectId = 0,
    .intervalMin = 20,
    .intervalMax = 20,
    .maxLatency = 0,
    .supervisionTimeout = 500,
};
static SsapMtuInfo g_delayTestMtuInfo = {
    .mtuSize = 256,
    .version = 1,
};
static SleErrorCode DeinitDelayTestClient(void);

void OnSleDelayTestFindStructureCallback(uint8_t clientId, uint16_t connectId
        , const ClientFindServiceRes *service, SleErrorCode errCode)
{
    if(connectId != g_delayTestConnectId) return;
    printf("OnSleDelayTestFindStructureCallback uuid:%s\r\n", service->uuid.uuid);
}

void OnSleDelayTestFindPropertyCallback(uint8_t clientId, uint16_t connectId
        , const ClientFindPropertyRes *property, SleErrorCode errCode)
{
    if(connectId != g_delayTestConnectId) return;
    printf("OnSleDelayTestFindPropertyCallback uuid:%s\r\n", property->uuid.uuid);
    if(memcmp(property->uuid.uuid, "DelayTestProp", strlen("DelayTestProp")) != 0) return;
    g_delayTestPropHdl = property->handle;
}

void OnSleDelayTestWriteConformCallback(uint8_t clientId, uint16_t connectId
        , const ClientWriteRes *writeResult, SleErrorCode errCode)
{
    if(connectId != g_delayTestConnectId) return;
}

void OnSleDelayTestExchangeInfoCallback(uint8_t clientId, uint16_t connectId
        , const SsapMtuInfo *exchangeInfo, SleErrorCode errCode)
{
    if(connectId != g_delayTestConnectId) return;
    if(exchangeInfo->mtuSize != g_delayTestMtuInfo.mtuSize) {
        printf("[SleDelayTestClient]OnSleDelayTestExchangeInfoCallback mtuSize:%lu\r\n", exchangeInfo->mtuSize);
        return;
    }
    osSemaphoreRelease(g_delayTestSemHdl);
}

void OnSleDelayTestNotificatedCallback(uint8_t clientId, uint16_t connectId
        , const ClientHandleValue *data, SleErrorCode errCode)
{
    if(connectId != g_delayTestConnectId) return;

}

void OnSleDelayTestIndicatedCallback(uint8_t clientId, uint16_t connectId
        , const ClientHandleValue *data, SleErrorCode errCode)
{
    if(connectId != g_delayTestConnectId) return;

}

void OnSleDelayTestConnStateChangeCallback(uint16_t connectId, const SleDeviceAddress *addr
        , SleConnectState connState, SlePairState pairState, SleDisConnectReason discReason)
{
    if(connectId != g_delayTestConnectId) return;
    if (connState == SLE_CONNECT_DISCONNECTED_STATE) {
        printf("[SleDelayTestClient]OnSleDelayTestConnStateChangeCallback disconnect\r\n");
        DeinitDelayTestClient();
    }
}

void OnSleDelayTestConnParamUpdatedCallback(uint16_t connectId, SleErrorCode errCode, const SleConnectionParamUpdateEvt *connParam)
{
    if(connectId != g_delayTestConnectId) return;
    if(connParam->supervisionTimeout != g_delayTestConnPara.supervisionTimeout) {
        printf("[SleDelayTestClient]OnSleDelayTestConnParamUpdatedCallback supervisionTimeout:%d\r\n", connParam->supervisionTimeout);
        return;
    }
    if(connParam->latency != g_delayTestConnPara.maxLatency) {
        printf("[SleDelayTestClient]OnSleDelayTestConnParamUpdatedCallback latency:%d\r\n", connParam->latency);
        return;
    }
    if(connParam->interval < g_delayTestConnPara.intervalMin ||
        connParam->interval > g_delayTestConnPara.intervalMax) {
        printf("[SleDelayTestClient]OnSleDelayTestConnParamUpdatedCallback interval:%d\r\n", connParam->interval);
        return;
    }
}

static SleConnectCallbacks connCbs = {
    .OnSleConnStateChangeCb = OnSleDelayTestConnStateChangeCallback,
    .OnSleConnParamUpdatedCb = OnSleDelayTestConnParamUpdatedCallback,
};

static SleSsapcCallbacks ssapcCbs = {
    .OnSleFindStructureCb = OnSleDelayTestFindStructureCallback,
    .OnSleFindPropertyCb = OnSleDelayTestFindPropertyCallback,
    .OnSleWriteCfmCb = OnSleDelayTestWriteConformCallback,
    .OnSleExchangeInfoCb = OnSleDelayTestExchangeInfoCallback,
    .OnSleNotificatedCb = OnSleDelayTestNotificatedCallback,
    .OnSleIndicatedCb = OnSleDelayTestIndicatedCallback,
};

SleErrorCode RegisterDelayTestClientCbs(void)
{
    SleErrorCode ret = SLE_ERR_UNKNOWN;
    ret = RegisterConnectCallbacks(&connCbs);
    if(ret != SLE_NO_ERROR) {
        printf("[SleDelayTestClient]RegisterConnectCallbacks failed(%lu)\r\n", ret);
        return ret;
    }
    ret = RegisterSsapClientCallbacks(&ssapcCbs);
    if(ret != SLE_NO_ERROR) {
        printf("[SleDelayTestClient]RegisterSsapClientCallbacks failed(%lu)\r\n", ret);
        return ret;
    }
    return SLE_NO_ERROR;
}

SleErrorCode UnregistertDelayTestCallbacks(void)
{
    SleErrorCode ret = SLE_ERR_UNKNOWN;
    ret = UnregisterConnectCallbacks(&connCbs);
    if(ret != SLE_NO_ERROR) {
        printf("[SleDelayTestClient]UnregisterConnectCallbacks failed(%lu)\r\n", ret);
        return ret;
    }
    ret = UnregisterSsapClientCallbacks(&ssapcCbs);
    if(ret != SLE_NO_ERROR) {
        printf("[SleDelayTestClient]UnregisterSsapClientCallbacks failed(%lu)\r\n", ret);
        return ret;
    }
    return SLE_NO_ERROR;
}

SleErrorCode InitDelayTestClient(void)
{
    osSemaphoreAttr_t attr = {
        .name = "DelayTestSem",
    };
    g_delayTestSemHdl = osSemaphoreNew(1, 0, &attr);
    //注册ssap client回调
    SleErrorCode ret = RegisterDelayTestClientCbs();
    if(ret != SLE_NO_ERROR) {
        printf("[SleDelayTestClient]RegisterDelayTestClientCbs failed(%lu)\r\n", ret);
        return ret;
    }
    //设置连接参数
    ret = SleUpdateConnParam(&g_delayTestConnPara);
    if(ret != SLE_NO_ERROR) {
        printf("[SleDelayTestClient]SleUpdateConnParam failed(%lu)\r\n", ret);
        return ret;
    }
    //设置MTU
    ret =SendExchangeInfoReq(g_delayTestClientId, g_delayTestConnectId, &g_delayTestMtuInfo);
    if(ret != SLE_NO_ERROR) {
        printf("[SleDelayTestClient]SendExchangeInfoReq failed(%lu)\r\n", ret);
        return ret;
    }
    osStatus_t result = osSemaphoreAcquire(g_delayTestSemHdl, 2000);
    if (result != osOK) {
        printf("[SleDelayTestClient]SendExchangeInfoReq sem failed(%lu)\r\n", result);
        return SLE_ERR_FAILED;
    }
    //添加delay test client
    SleUuid clientUuid;
    memcpy(clientUuid.uuid, "DelayTestClient", strlen("DelayTestClient") + 1);
    clientUuid.len = strlen("DelayTestClient") + 1;
    ret = AddSspaClient(&clientUuid, &g_delayTestClientId);
    //获取对端delay test property handle
    ClientFindStructure stru = {
        .findType = SSAP_FIND_TYPE_PROPERTY_TYPE,
        .startHandle = 1,
        .endHandle = 0xffff,
    };
    ret = FindSsapStructure(g_delayTestClientId, g_delayTestConnectId, &stru);
    if(ret != SLE_NO_ERROR) {
        printf("[SleDelayTestClient]FindSsapStructure failed(%lu)\r\n", ret);
        return ret;
    }
    return SLE_NO_ERROR;
}

SleErrorCode DeinitDelayTestClient(void)
{
    SleErrorCode ret = SLE_ERR_UNKNOWN;
    ret = RemoveClient(g_delayTestClientId);
    if(ret != SLE_NO_ERROR) {
        printf("[SleDelayTestClient]RemoveClient failed(%lu)\r\n", ret);
        return ret;
    }
    g_delayTestPropHdl = 0;
    g_delayTestClientId = 0;

    ret = UnregistertDelayTestCallbacks();
    if(ret != SLE_NO_ERROR) {
        printf("[SleDelayTestClient]UnregistertDelayTestCallbacks failed(%lu)\r\n", ret);
        return ret;
    }
    g_delayTestConnectId = 0;
    osSemaphoreDelete(g_delayTestSemHdl);
    g_delayTestSemHdl = 0;
    osThreadTerminate(g_delayTestThreadId);
    g_delayTestThreadId = 0;
    return SLE_NO_ERROR;
}

void StartDelayTest(void)
{
    if(g_delayTestPropHdl == 0) {
        printf("[SleDelayTestClient]g_delayTestPropHdl is NULL, StartDelayTest fail\r\n");
        return;
    }
    SleErrorCode ret = SLE_ERR_UNKNOWN;
    uint16_t DelayTestStep = 0;
    uint8_t DelayTestSendSeq = 0;
    uint8_t *data = (uint8_t*)malloc(g_test_data_len * sizeof(uint8_t));
    memset(data, 'C', g_test_data_len);
    ClientWriteParam param = {
        .handle = g_delayTestPropHdl,
        .type = SLE_SSAP_PROPERTY_TYPE,
        .dataLength = g_test_data_len,
    };
    while (DelayTestStep++ < g_test_steps) {
        // 发送start message
        DelayTestSendSeq = 0;
        //发送data message
        while (DelayTestSendSeq++ < g_test_times) {
            data[0] = DelayTestSendSeq;
            param.data = data;
            if (g_isReq == 1) {
                ret = SendWriteReq(g_delayTestClientId, g_delayTestConnectId, &param);
            } else {
                ret = SendWriteCmd(g_delayTestClientId, g_delayTestConnectId, &param);
            }
            if(ret != SLE_NO_ERROR) {
                printf("[SleDelayTestClient]Send data(seq:%d) failed(%lu)\r\n",data[0], ret);
            }
        }
    }
    free(data);
    osal_printk("KHTestWrite exit\r\n");
    DeinitDelayTestClient();
}

void DelayTestClient(void)
{
    SleErrorCode ret = SLE_ERR_UNKNOWN;
    g_delayTestConnectId =  SleGetInputNumber("please input connectId:");
    g_test_times = SleGetInputNumber("please input test times:");
    g_test_steps = SleGetInputNumber("please input test steps:");
    g_test_data_len = SleGetInputNumber("please input test data len:");
    g_isReq = SleGetInputNumber("please input isReq:");
    g_delayTestConnPara.connectId = g_delayTestConnectId;
    if (CheckIsConnected(g_delayTestConnectId) != SLE_NO_ERROR) {
        SLE_TEST_TOOL_LOG("[SleDelayTestClient]connectId(%d) is not connected", g_delayTestConnectId);
        return;
    }
    ret = InitDelayTestClient();
    if(ret != SLE_NO_ERROR) {
        SLE_TEST_TOOL_LOG("[SleDelayTestClient]InitDelayTestServer failed(%lu)", ret);
        goto fail;
    }
    osThreadAttr_t attr = {
        .name = "DelayTestClient",
        .priority = osPriorityNormal,
        .stack_size = 1024 * 3,
    };
    g_delayTestThreadId = osThreadNew((osThreadFunc_t)StartDelayTest, NULL, &attr);
    return;
fail:
    DeinitDelayTestClient();
    return;
}